#include "Renderer.h"
#include "Node.h"
#include "Geometry.h"

namespace graphics
{

Renderer::~Renderer()
{
	m_VertexBuffer = 0;
	m_Device = 0;
}
void Renderer::Initialize(D3DDevice DevicePtr)
{
	m_Device = DevicePtr;
}
void Renderer::DrawScene(Node* NodePtr)
{
	if(NodePtr != NULL)
	NodePtr->onDraw(*this);
}
void Renderer::Draw(Geometry* GeometryPtr)
{
	m_Geometry = GeometryPtr;
	m_VertexBuffer = GeometryPtr->getVertexBuffer();
	m_VertexType = GeometryPtr->getVertexType();
	
	UpdateRenderStates();
	DrawPrimitive();
}
void Renderer::UpdateRenderStates()
{
	//Go back to default states
	m_Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
	m_Device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

	//Begin updating render states
	std::vector<RS> RenderStates = m_Geometry->GetRenderStates();
	std::vector<RS>::iterator Iter;
	for(Iter = RenderStates.begin(); Iter != RenderStates.end(); Iter++)
	{
		//WIREFRAME
		if((*Iter).RS_Type == RS::RS_WIREFRAME)
		{
			m_Device->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
		}//WIREFRAME end

		//ALPHA BLENDING
		if((*Iter).RS_Type == RS::RS_ALPHABLEND)
		{
			m_Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
			
			RS_AlphaBlend value = m_Geometry->GetRenderState_AlphaBlend();

			if(value.Source == RS_AlphaBlend::BLEND_ZERO)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
			else if(value.Source == RS_AlphaBlend::BLEND_ONE)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
			else if(value.Source == RS_AlphaBlend::BLEND_SRCCOLOR)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR);
			else if(value.Source == RS_AlphaBlend::BLEND_INVSRCCOLOR)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVSRCCOLOR);
			else if(value.Source == RS_AlphaBlend::BLEND_SRCALPHA)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
			else if(value.Source == RS_AlphaBlend::BLEND_INVSRCALPHA)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVSRCALPHA);
			else if(value.Source == RS_AlphaBlend::BLEND_DESTALPHA)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTALPHA);
			else if(value.Source == RS_AlphaBlend::BLEND_INVDESTALPHA)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVDESTALPHA);
			else if(value.Source == RS_AlphaBlend::BLEND_DESTCOLOR)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR);
			else if(value.Source == RS_AlphaBlend::BLEND_INVDESTCOLOR)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVDESTCOLOR);
			else if(value.Source == RS_AlphaBlend::BLEND_SRCALPHASAT)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHASAT);
			else if(value.Source == RS_AlphaBlend::BLEND_BOTHSRCALPHA)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_BOTHSRCALPHA);
			else if(value.Source == RS_AlphaBlend::BLEND_BOTHINVSRCALPHA)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_BOTHINVSRCALPHA);
			else if(value.Source == RS_AlphaBlend::BLEND_BLENDFACTOR)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_BLENDFACTOR);
			else if(value.Source == RS_AlphaBlend::BLEND_INVBLENDFACTOR)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVBLENDFACTOR);
			else if(value.Source == RS_AlphaBlend::BLEND_SRCCOLOR2)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR2);
			else if(value.Source == RS_AlphaBlend::BLEND_INVSRCCOLOR2)
				m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVSRCCOLOR2);

			if(value.Destination == RS_AlphaBlend::BLEND_ZERO)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
			else if(value.Destination == RS_AlphaBlend::BLEND_ONE)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
			else if(value.Destination == RS_AlphaBlend::BLEND_SRCCOLOR)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);
			else if(value.Destination == RS_AlphaBlend::BLEND_INVSRCCOLOR)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR);
			else if(value.Destination == RS_AlphaBlend::BLEND_SRCALPHA)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA);
			else if(value.Destination == RS_AlphaBlend::BLEND_INVSRCALPHA)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
			else if(value.Destination == RS_AlphaBlend::BLEND_DESTALPHA)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTALPHA);
			else if(value.Destination == RS_AlphaBlend::BLEND_INVDESTALPHA)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVDESTALPHA);
			else if(value.Destination == RS_AlphaBlend::BLEND_DESTCOLOR)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTCOLOR);
			else if(value.Destination == RS_AlphaBlend::BLEND_INVDESTCOLOR)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVDESTCOLOR);
			else if(value.Destination == RS_AlphaBlend::BLEND_SRCALPHASAT)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHASAT);
			else if(value.Destination == RS_AlphaBlend::BLEND_BOTHSRCALPHA)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_BOTHSRCALPHA);
			else if(value.Destination == RS_AlphaBlend::BLEND_BOTHINVSRCALPHA)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_BOTHINVSRCALPHA);
			else if(value.Destination == RS_AlphaBlend::BLEND_BLENDFACTOR)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_BLENDFACTOR);
			else if(value.Destination == RS_AlphaBlend::BLEND_INVBLENDFACTOR)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVBLENDFACTOR);
			else if(value.Destination == RS_AlphaBlend::BLEND_SRCCOLOR2)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR2);
			else if(value.Destination == RS_AlphaBlend::BLEND_INVSRCCOLOR2)
				m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR2);

			//Alpha Map: Takes the alpha from the alpha map
			m_Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
			m_Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);

			//Texture: Takes the color from the Texture, takes the Alpha Map from the previous stage
			m_Device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
			m_Device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);

			m_Device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
			m_Device->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
		}//ALPHA BLENDING end
	}
}
void Renderer::DrawPrimitive()
{
	if( m_VertexBuffer == 0 ) return;
	m_Device->SetTransform(D3DTS_WORLD, &(m_Geometry->World));
	m_Device->SetRenderState( D3DRS_LIGHTING, FALSE );

	if(m_VertexType == V_Type_P)
	{
		m_Device->SetStreamSource(0, m_VertexBuffer, 0, sizeof(V_P));
		m_Device->SetVertexDeclaration(V_P::V_Declaration);
		m_Device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, m_Geometry->V_Vector_P.size()-2);
	}

	if(m_VertexType == V_Type_PC)
	{
		m_Device->SetStreamSource(0, m_VertexBuffer, 0, sizeof(V_PC));
		m_Device->SetVertexDeclaration(V_PC::V_Declaration);
		m_Device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, m_Geometry->V_Vector_PC.size()-2);
	}

	if(m_VertexType == V_Type_PT)
	{
		m_Device->SetStreamSource(0, m_VertexBuffer, 0, sizeof(V_PT));
		m_Device->SetVertexDeclaration(V_PT::V_Declaration);
		m_Device->SetTexture(0, m_Geometry->P_Texture);
		m_Device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0,m_Geometry->V_Vector_PT.size()-2);
	}
}

}/* namespace graphics */